
import { _decorator, Component, Vec3, input, Input, EventMouse, Node, Prefab, KeyCode, EventKeyboard, error, resources, instantiate } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('GameManager')
export class GameManager extends Component {

    @property({ type: Node })
    private obj: Node = null;

    @property({ type: Node })
    private centerPlane: Node = null;

    // 是否接收到跳跃指令
    private _startJump: boolean = false;

    // 跳跃步长
    private _jumpStep: number = 0;
    // 每次跳跃时常
    private _jumpTime: number = 0.1;

    private _curJumpTime: number = 0;  // 当前跳跃时间
    private _curJumpSpeed: number = 0; // 当前跳跃速度

    private _curPos: Vec3 = new Vec3();    // 当前角色位置
    private _targetPos: Vec3 = new Vec3(); // 角色目标位置

    private _jumpDirect: number = 0;  // 0 上 1 下 2 左 3 右

    // 每次跳跃过程中，当前帧移动位置差
    private _deltaPos: Vec3 = new Vec3(0, 0, 0);

    private _boardLimit: number = 4.7;  // 边界距离，不可超过

    private _planeDistance: number = 0;

    start () {
        console.log('GameManager');

        input.on(Input.EventType.MOUSE_UP, this.onMouseUp, this);
        input.on(Input.EventType.KEY_UP, this.onKeyUp, this);
    }

    onKeyUp(event: EventKeyboard) {
        switch(event.keyCode) {
            case KeyCode.KEY_A:
                this.jumpByStep(2);
                break;
            case KeyCode.KEY_D:
                this.jumpByStep(3);
                break;
            case KeyCode.KEY_W:
                this.jumpByStep(0);
                break;
            case KeyCode.KEY_S:
                this.jumpByStep(1);
                break;
            default:
                console.log('release other key', event.keyCode);
        }
    }

    onMouseUp(event: EventMouse) {
        if (event.getButton() === 0) {
            this.createPlane();
        }
    }

    loadRes(url: string, type: any, cb: Function = ()=>{}) {
        resources.load(url, (err: any, res: any)=>{
            if (err) {
                error(err.message || err);
                cb(err, res);
                return;
            }

            cb && cb(null, res);
        })
    }

    loadModelRes (modulePath: string) {
        return new Promise((resolve, reject)=>{
            this.loadRes(`${modulePath}`, Prefab, (err: any, prefab: Prefab)=>{
                if (err) {
                    console.error("model load failed", modulePath);
                    reject && reject();
                    return;
                }

                resolve && resolve(prefab);
            })
        })
    }

    createPlane() {
        // plane 不能直接 new，因为 new 出来也不是一个结点，需要从 prefab 中实例化

        this._planeDistance = this._planeDistance + 10;
        // let plane1 = new geometry.Plane(1, 1, 1, this._planeDistance);
        // plane1.setPosition(new Vec3(Number(this._planeDistance), Number(this._planeDistance), Number(this._planeDistance)));
        // console.log("create plane", plane1);

        this.loadModelRes("MyPlane").then((prefab: any)=>{
            let node1 = instantiate(prefab);
            // y 不需要改变，z 为 0 则表示和其他方块在一个水平线上
            // x 加 10 是因为，从方块中心到边界的距离是 5，那么第一个方块的中心是 (0, 0) 的话，第二个就是 (10, 0)
            node1.setPosition(new Vec3(Number(this._planeDistance), 0, 0));
            // node1.setScale(new Vec3(1, 1, 1));
            node1.active = true;
            node1.parent = this.node;
        });
    }

    jumpByStep(direction: number) {
        if (this._startJump) {
            return;
        }

        if (direction === this._jumpDirect) {
            if (direction === 2 || direction === 3) {
                if (Math.abs(this._curPos.x) >= this._boardLimit) {
                    console.log("左右到达边界无法跳跃");
                    return;
                }
            }

            if (direction === 0 || direction === 1) {
                if (Math.abs(this._curPos.z) >= this._boardLimit) {
                    console.log("上下到达边界无法跳跃");
                    return;
                }
            }
        }

        this._jumpDirect = direction;
        this._startJump = true;
        this._jumpStep = 1;  // 默认步长是 1
        this._curJumpTime = 0;
        this._curJumpSpeed = this._jumpStep / this._jumpTime;
        this.obj.getPosition(this._curPos);

        if (this._jumpDirect === 3) {
            Vec3.add(this._targetPos, this._curPos, new Vec3(this._jumpStep, 0, 0));
        } else if (this._jumpDirect === 2) {
            Vec3.subtract(this._targetPos, this._curPos, new Vec3(this._jumpStep, 0, 0));
        } else if (this._jumpDirect === 0) {
            // "向上" 是 z 的负方向
            Vec3.subtract(this._targetPos, this._curPos, new Vec3(0, 0, this._jumpStep));
        } else if (this._jumpDirect === 1) {
            Vec3.add(this._targetPos, this._curPos, new Vec3(0, 0, this._jumpStep));
        }

        console.log(`this._targetPos=${this._targetPos.x}, ${this._targetPos.y}, ${this._targetPos.z}`);
    }

    update (deltaTime: number) {
        // console.log("plane pos=", this.centerPlane.getPosition());

        /**
         * 整个物体的移动是：先设定一个目标位置，然后每帧向目标位置移动，通过时间决定是否移动到目标位置
         */
        if (this._startJump) {
            this._curJumpTime += deltaTime;
            if (this._curJumpTime > this._jumpTime) {
                this.obj.setPosition(this._targetPos);  // 设置最终位置
                this._startJump = false;
            } else {
                // tween 设置从起点到终点的过渡位置
                this.obj.getPosition(this._curPos);
                console.log(this._curPos);

                // TODO 下面代码比较繁琐，可以精简
                if (this._jumpDirect === 3) {
                    this._deltaPos.x = this._curJumpSpeed * deltaTime;
                    this._deltaPos.z = 0;
                    Vec3.add(this._curPos, this._curPos, this._deltaPos);
                    if (this._curPos.x >= this._boardLimit) {
                        this._curPos.x = this._boardLimit;
                    }
                } else if (this._jumpDirect === 2) {
                    this._deltaPos.x = this._curJumpSpeed * deltaTime;
                    this._deltaPos.z = 0;
                    Vec3.subtract(this._curPos, this._curPos, this._deltaPos);
                    // 注意：此处不能携程 Math.abs(this._curPos.x) >= this._boardLimit
                    // 因为有一种场景，就是我一直向左移动，移动到边界，然后向右移动，这时候，如果通过绝对值来判断，则会直接把
                    // 边界值置为其相反值，而导致物体瞬间跳跃到最右边，然后又回复到正确的位置
                    if (this._curPos.x <= -this._boardLimit) {
                        this._curPos.x = -this._boardLimit;
                    }
                }
                // "向上" 是 z 的负方向
                else if (this._jumpDirect === 0) {
                    this._deltaPos.z = this._curJumpSpeed * deltaTime;
                    this._deltaPos.x = 0;
                    Vec3.subtract(this._curPos, this._curPos, this._deltaPos);
                    if (this._curPos.z <= -this._boardLimit) {
                        this._curPos.z = -this._boardLimit;
                    }
                } else if (this._jumpDirect === 1) {
                    this._deltaPos.z = this._curJumpSpeed * deltaTime;
                    this._deltaPos.x = 0;
                    Vec3.add(this._curPos, this._curPos, this._deltaPos);
                    if (this._curPos.z >= this._boardLimit) {
                        this._curPos.z = this._boardLimit;
                    }
                }

                this.obj.setPosition(this._curPos);
            }
        }
    }
}

